
package com.ruoyi.schedule;

import com.github.s7connector.api.S7Connector;
import com.github.s7connector.api.S7Serializer;
import com.github.s7connector.api.factory.S7ConnectorFactory;
import com.github.s7connector.api.factory.S7SerializerFactory;
import com.ruoyi.config.PLCSetting;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 定时循环处理PLC数据，可以读取和写入
 */

@Slf4j
//@Configuration
public class ScheduledHandler {

    @Resource
    private PLCSetting plcSetting;
    public static Map<String, DataBlockInfo> dataBlockInfoMap = new HashMap<>();
    private ScheduledExecutorService executorService = Executors.newScheduledThreadPool(16);

  //  @PostConstruct
    public void init() {

        if (!CollectionUtils.isEmpty(plcSetting.getDevices())) {

            plcSetting.getDevices().forEach(plc -> {

                S7Connector s7Connector = S7ConnectorFactory
                        .buildTCPConnector()
                        .withHost(plc.getIp())
                        .withPort(plc.getPort())
                        .withTimeout(plc.getConnectTimeout()) //连接超时时间
                        .withRack(plc.getRack())
                        .withSlot(plc.getSlot())
                        .build();

                S7Serializer s7Serializer = S7SerializerFactory.buildSerializer(s7Connector);
                if (!CollectionUtils.isEmpty(plc.getDataBlock())) {
                    plc.getDataBlock().forEach(dataBlock -> {
                        //开启轮询读取数据
                        if (dataBlock.isReadRepeat()) {
                            try {
                                Class<?> clazz = getClass().getClassLoader().loadClass(dataBlock.getEntityClassName());
                                executorService.scheduleWithFixedDelay(() -> {
                                    try {
                                        //读取数据
                                        Object data = s7Serializer.dispense(clazz, dataBlock.getDatabaseNumber(), dataBlock.getOffset());
                                        //TODO data
                                        if (log.isInfoEnabled()) {
                                            log.info("{}: [{}]", data.getClass(), data);
                                        }
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }
                                }, 10000, dataBlock.getReadRepeatInterval(), TimeUnit.MILLISECONDS);
                            } catch (ClassNotFoundException e) {
                                e.printStackTrace();
                            }
                        }

                        //缓存连接信息
                        DataBlockInfo dataBlockInfo = new DataBlockInfo();
                        dataBlockInfo.setS7Connector(s7Connector);
                        dataBlockInfo.setS7Serializer(s7Serializer);
                        dataBlockInfo.setDataBlock(dataBlock);
                        dataBlockInfoMap.put(dataBlock.getEntityClassName(), dataBlockInfo);
                    });
                }
            });
        }

    }


/**
     * 数据块缓存用的内部类
     */

    public static class DataBlockInfo {

        private PLCSetting.DataBlock dataBlock;
        private S7Serializer s7Serializer;
        private S7Connector s7Connector;

        public PLCSetting.DataBlock getDataBlock() {
            return dataBlock;
        }
        public void setDataBlock(PLCSetting.DataBlock dataBlock) {
            this.dataBlock = dataBlock;
        }

        public S7Serializer getS7Serializer() {
            return s7Serializer;
        }

        public void setS7Serializer(S7Serializer s7Serializer) {
            this.s7Serializer = s7Serializer;
        }

        public S7Connector getS7Connector() {
            return s7Connector;
        }

        public void setS7Connector(S7Connector s7Connector) {
            this.s7Connector = s7Connector;
        }
    }
}
